#UnrealEngine5 でHTTPリクエスト機能を実装してAPIコールしてみた
こんにちは、ゲームソリューショングループの入井です。
Unreal Engineで実行中のゲームと外部のWeb APIを連携したい時は、HTTPリクエストをゲーム内から飛ばす必要があります。しかし、Unreal EngineのBluePrintは標準でHTTPリクエストの機能を持っていません。HTTP通信用のモジュールは入っているため、それらを呼び出すC++コードを書いて自分で機能を実装する必要があります。
今回の記事ではWeb APIからJSONデータを取得し、それをUEエディタのログに流す機能を作成していきます。
尚、基本的な部分については以下の動画を参考にさせていただきました。
動画ではゲームスタートと同時にリクエストが走るようになっていますが、この記事ではゲーム画面上のボタンをクリックされたらリクエストが走るという形にアレンジしています。
実行環境
- Unreal Engine 5.0.3
Unreal Engineでの作業
C++プロジェクトの作成
Unreal EngineでC++を使用するためには、プロジェクト作成時に以下の画像のようにC++を選択する必要があります。(プロジェクト作成後も変更可能です)
尚、初めてC++ Projectを作る場合は、Visual Studioをインストールするよう警告メッセージが表示されるため、インストール作業が必要になります。
その際、Visual Studioの言語パックに日本語を含めると、C++コンパイル時等のログが文字化けするため、英語で設定することをおすすめします。(一応、日本語のまま使う方法もあるようなのですが、設定に結構手間がかかります)
また、Visual Studioの他に.Net Core Runtimeも必要です。無いとプロジェクト作成時に怒られます。
ビルド設定の変更
プロジェクトの作成が完了したら、Visual Studio等のエディタでプロジェクトのディレクトリを開きます。そして、Source/{プロジェクト名}/{プロジェクト名}.Build.csを開き、以下のようにPublicDependencyModuleNames.AddRange()
にHTTP
モジュールとJson
モジュールを追加します。
※cppTestとなっている箇所は、私の作業時のプロジェクト名が入っています。
using UnrealBuildTool; public class cppTest : ModuleRules { public cppTest(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HTTP", "Json" }); PrivateDependencyModuleNames.AddRange(new string[] { }); } }
これで、このプロジェクトのC++コードでHTTPとJSON関係のモジュールが使用できるようになります。
HTTP通信用汎用クラス作成
Unreal Editorに戻り、Content BrowserでC++ Classesディレクトリを開き、何もない場所で右クリックしてメニュー内のNew C++ Class…を選択します。
親クラスの選択ダイアログが表示されるので、Noneを選択してNextをクリックします。
Name欄にHttpRequestと入力し、Create Classをクリックすると新しいC++クラスが自動的に作成されます。
コードエディタを開き、以下のようにヘッダファイルでHttp.hのIncludeと関数の定義を追加します。
#pragma once #include "CoreMinimal.h" #include "Http.h" /** * */ class CPPTEST_API HttpRequest { public: HttpRequest(); ~HttpRequest(); void OnRequest(const FString Url, const FString Verb); private: static void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool ConnectionSuccessfully); };
OnRequeste()
が外部から呼び出しを受けてHTTPリクエストを実行する関数で、OnResponseReceived()
がHTTPレスポンスを受け取った際に行う処理を書く関数です。
次に、各関数の実装部分を書いていきます。
#include "HttpRequest.h" #include "Json.h" HttpRequest::HttpRequest() { } HttpRequest::~HttpRequest() { } void HttpRequest::OnRequest(const FString Url, const FString Verb) { // HTTPリクエストオブジェクト作成 const FHttpRequestRef Request = FHttpModule::Get().CreateRequest(); // HTTPリクエスト完了時に実行する関数のポインタをセット Request->OnProcessRequestComplete().BindStatic(&HttpRequest::OnResponseReceived); // HTTPリクエストのURLをセット Request->SetURL(Url); // HTTPリクエストのメソッドをセット Request->SetVerb(Verb); // HTTPリクエスト実行 Request->ProcessRequest(); } void HttpRequest::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool ConnectionSuccessfully) { // JSONオブジェクト格納用変数初期化 TSharedPtr<FJsonObject> ResponseObj = MakeShareable(new FJsonObject()); // 文字列からJSONを読み込むためのReader初期化 TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString()); // 文字列からJSONオブジェクトへデシリアライズ if (FJsonSerializer::Deserialize(Reader, ResponseObj)) { // UEでログ出力(APIから受け取った文字列そのまま) UE_LOG(LogTemp, Display, TEXT("Response %s"), *Response->GetContentAsString()); // UEでログ出力(JSONからnameキーの文字列のみ出力) UE_LOG(LogTemp, Display, TEXT("Name %s"), *ResponseObj->GetStringField("name")); } }
各行の処理の意味はコメントの通りです。
OnRequeste()
でリクエスト先のURLとどのHTTPメソッドで通信するかを外部から受け取る形になっており、このクラスを使えば何処からでも好きなWEB APIに向けてHTTPリクエストが行えるようになっています。
ビルドが問題なく完了したら、クラスの作成は完了です。
C++クラスからAPIコールBluePrint作成
ボタンUIからリクエストを受け取るためのBluePrintを作成します。
普通のBluePrintクラスからC++クラスは呼び出せないので、先ほどと同じようにContent BrowserからC++クラスの作成を始めます。
今度はUIのBluePrintと連携させたいので、親クラスとしてActorを選択します。
クラス名はApiTestとして、C++クラスの作成を実行します。
コードエディタを開き、作成されたヘッダファイルに以下のようにSendRequest()
関数を追加します。
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "ApiTest.generated.h" UCLASS() class CPPTEST_API AApiTest : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties AApiTest(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; UFUNCTION(BlueprintCallable, Category="Http") void SendRequest(); };
UNFUNCTION()
というマクロをSendRequeset()
の上に書いており、こうすることによってUEのBluePrintから関数を呼び出せるようになります。BluprintCallable等の設定値については以下のサイト等が参考になります。
次に関数の実装部分を書いていきます。
#include "ApiTest.h" #include "HttpRequest.h" // Sets default values AApiTest::AApiTest() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; } // Called when the game starts or when spawned void AApiTest::BeginPlay() { Super::BeginPlay(); } // Called every frame void AApiTest::Tick(float DeltaTime) { Super::Tick(DeltaTime); } void AApiTest::SendRequest() { HttpRequest Request; Request.OnRequest("https://jsonplaceholder.typicode.com/users/1", "GET"); }
色々書いてありますが、ヘッダファイルの呼び出しとSendRequest()
内の実装を少し書いただけです。SendRequest()
内では、先ほど作ったHttpRequestクラスのインスタンスを使ってHTTPリクエストを実行しています。
HTTPリクエストの送信先URLは、ダミーのJSONデータを返してくれるフリーWeb APIです。users/{:id}
パスにリクエストを送ることで、ランダムなユーザーデータっぽいJSONを返してくれます。
ビルドが問題なく通るのを確認したら、Unreal Editorに戻ってContent Browser内にApiTestが作成されているので、それを右クリックします。
メニューからCreate BluePrint class based on ApiTestを選択します。
これにより、今作成したC++クラスを元にしたBluePrintが作成されます。
作成されたBluePrintをドラッグしてゲーム画面内に配置したら、HTTPを呼び出すための準備は完了です。
ボタンUI WidgetからAPIコールBluePrint実行
Content Browser内で右クリックし、今度はUser Interface → Widget BluePrintを選択してUI用のBluePrintを作成します。
作成したBluePrintの編集画面に入り、適当にCanvas PanelとButton、Textを配置します。
ここでの配置どおりにゲーム画面上にUIが表示されます。詳細は、UEでのUI作成について解説しているサイト等をご参照ください。
編集画面右上のGraphタブをクリックしてUIのBluePrintノード編集画面に入ります。
以下のようにボタンのOn Clickedイベントを起点にしたノードを設定します。
Get Actor Of Classノードでゲーム画面上にさきほど配置したApi Test Actorを取得し、それを参照してSendRequest関数を実行しています。SendRequestノードは、先ほどC++のヘッダファイルでUFUNCTIONマクロを設定したことで、この画面で呼び出せるようになっています。
これでUIの処理は作成完了したので、Level BluePrintの編集画面を開き、ゲーム画面上にUIが表示されるようノードを配置します。
ゲーム開始とともにBeginPlayイベントが送信され、Create Button WidgetでUIが作成、それをAdd to Viewportでゲーム画面に配置、という処理の流れです。Create Button Widgetで設定しているButton クラスは先ほど作成したUI BluePrintのクラス名です。
実行結果
ゲームプレイを開始し、画面中央に表示されたボタンをクリックします。
Unreal Editorのログに以下のようにWeb APIから取得したJSONのテキストが表示されます。これにより、HTTPリクエストが問題なく完了したことが確認できました。
LogTemp: Display: Response { "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "[email protected]", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" } } LogTemp: Display: Name Leanne Graham
まとめ
Unreal Engineのゲーム画面上からHTTPリクエストを送信し、WebAPIからのデータを取得することができました。
今回は単純にログにデータを流すだけでしたが、取得したデータをゲーム画面上に展開するなどすれば、様々なWeb APIと連携してゲームの機能を拡張していけると思われます。